
#include "StdAfx.h"
#include "GaitAnaly.h"
#include "PROCESS.H"
#include "../Frame/GYWalkAidApp.h"
#include "../Common/CommonDef.h"
#include "../Common/CommonFun.h"
#include "../Common/GYDataSet.h"
#include "../Common/SmartWAParam.h"
#include "../Common/ColorCombo.h"

extern volatile BOOL g_bAppQuit;

CGaitAnaly::CGaitAnaly(CWnd* pDrawCtrl, int nWAIndex)
{
	ASSERT(pDrawCtrl);
	ASSERT(nWAIndex >= 0);

	m_hDrawThread	= NULL;
	m_pDrawCtrl		= pDrawCtrl;
	m_nDevIndex		= nWAIndex;
	m_dwCommVer		= 0;

	m_bNotifyStop	= FALSE;

	ZERO_ARRAY(m_aGaitPoints);
	m_nArrayPos		= -1;

	m_crWAColor		= RGB(255, 255, 255);
	m_bGaitPause	= FALSE;
	m_nLineWidthMul	= 1;
}

CGaitAnaly::CGaitAnaly()
{
	m_hDrawThread	= NULL;
	m_pDrawCtrl		= NULL;
	m_nDevIndex		= -1;
	m_dwCommVer		= 0;
	
	m_bNotifyStop	= FALSE;
	
	ZERO_ARRAY(m_aGaitPoints);
	m_nArrayPos		= -1;

	m_crWAColor		= RGB(255, 255, 255);
	m_bGaitPause	= FALSE;
	m_nLineWidthMul	= 1;
}


CGaitAnaly::~CGaitAnaly()
{

}

BOOL CGaitAnaly::SetGaitPara(WA_BASIC_PARA* pBasicPara)
{
	m_BasicPara = *pBasicPara;
	return TRUE;
}

BOOL CGaitAnaly::StartDraw()
{
	if(m_hDrawThread)
	{
		ASSERT(FALSE);
		WaitForSingleObject(m_hDrawThread, INFINITE);
	}

	UINT unThreadID			= 0;
	m_hDrawThread			=(HANDLE)_beginthreadex(NULL,0, DrawGaitThread, (LPVOID)this, 0, &unThreadID); 
	
	return TRUE;
}

BOOL CGaitAnaly::StopDraw()
{
	CWAManager* pWAMan = GetApp()->GetWAMan();
	if(!pWAMan)
	{
		ASSERT("Get WAManager Failed!" == NULL);
		return 0;
	}

	if(m_hDrawThread)
	{
		m_bNotifyStop = TRUE;
		WaitForSingleObject(m_hDrawThread, INFINITE);

		m_hDrawThread = NULL;
		m_bNotifyStop = FALSE;
	}

	pWAMan->cmdStopReadGait(m_nDevIndex);

	return TRUE;
}

UINT CGaitAnaly::DrawGaitThread(LPVOID lpParam)
{
	CGaitAnaly* pThis = (CGaitAnaly*)lpParam;
	ASSERT(pThis);

	CWAManager* pWAMan = GetApp()->GetWAMan();
	if(!pWAMan)
	{
		ASSERT("Get WAManager Failed!" == NULL);
		return 0;
	}

	while(!pWAMan->IsWAConnected(pThis->m_nDevIndex))
	{
		if(pThis->m_bNotifyStop)
			return 0;

		if(g_bAppQuit)
			return 0;

		Sleep(200);
	}

	//  Get color index of WA
	pThis->m_dwCommVer = pWAMan->GetWACommVersion(pThis->m_nDevIndex);
	if(pThis->m_dwCommVer >= 0x12)
	{
		int nColorIndex = 0;

		CString strSQL;
		strSQL.Format(_T("SELECT ColorIndex FROM WAColor WHERE WAAddress='%s'"), pWAMan->GetWAAddress(pThis->m_nDevIndex));
		
		CGYDataSet setWAColor(strSQL);
		if(!setWAColor.IsEOF())
		{
			CString strColorIndex;
			setWAColor.GetFieldValue(_T("ColorIndex"), strColorIndex);
			
			nColorIndex = _ttoi(strColorIndex);
		}

		pThis->m_crWAColor = CColorComboBox::GetWAColor(nColorIndex);
	}

	Sleep(200);
	WA_BASIC_PARA wbpBasicPara = pWAMan->cmdGetBasicPara(pThis->m_nDevIndex);
	pThis->SetGaitPara(&wbpBasicPara);

	Sleep(300);
	pThis->m_strDevID = pWAMan->GetWADevID(pThis->m_nDevIndex);

	Sleep(300);
	BOOL bRetStart = pWAMan->cmdStartReadGait(pThis->m_nDevIndex);
	if(!bRetStart)
	{
		CString strMsg = GetResString(IDS_RT_START_GAIT_FAIL);
		GetApp()->GetCustMsgCenter()->PostStringMessage(GYWA_MSG_BLUETOOTH_CONNECT_PROGRESS, strMsg, INFINITE);
	}

	pThis->BeginDraw();

	while(!pThis->m_bNotifyStop)
	{
		pThis->m_nArrayPos++;
		if(pThis->m_nArrayPos >= GAIT_POINT_ARRAY_SIZE)
			pThis->m_nArrayPos = 0;

		DWORD dwGait = pWAMan->cmdReadGaitValue(pThis->m_nDevIndex);
		pThis->m_aGaitPoints[pThis->m_nArrayPos] = dwGait;

		if(!pThis->m_bGaitPause)
			pThis->DrawGaitGraph();
	}

	pThis->DrawStopGraph();

	pThis->EndDraw();

	return 0;
}


BOOL CGaitAnaly::BeginDraw(BOOL bDrawInCtrl/* = TRUE*/)
{
	if(bDrawInCtrl)
	{
		ASSERT(m_pDrawCtrl);

		if(m_pDrawCtrl && ::IsWindow(m_pDrawCtrl->GetSafeHwnd()))
		{
			m_pDrawCtrl->GetClientRect(&m_rectCtrl);
			m_pDC = m_pDrawCtrl->GetDC();
		}
		else
		{
			GYMsgBox(IDS_RT_INVALID_LABEL, MB_OK|MB_ICONSTOP);
			return FALSE;
		}
	}

	m_MemDC.CreateCompatibleDC(m_pDC);
	
	m_ptZero.x = m_rectCtrl.Width() * MARGIN_RATIO;
	m_ptZero.y = m_rectCtrl.Height() * (1 - MARGIN_RATIO);
	
	m_MemBitmap.CreateCompatibleBitmap(m_pDC, m_rectCtrl.Width(), m_rectCtrl.Height());
	m_pOldBitmap = m_MemDC.SelectObject(&m_MemBitmap);
	
	m_brushWhite.CreateSolidBrush(RGB(255,255,255));
	m_brushWAColor.CreateSolidBrush(m_crWAColor);
	m_brushRed.CreateSolidBrush(RGB(255, 0, 0));
	m_brushBlue.CreateSolidBrush(RGB(0, 0, 255));
	m_brushBlack.CreateSolidBrush(RGB(0, 0, 0));

	m_pen1Black.CreatePen(PS_SOLID, 1 * m_nLineWidthMul, RGB(0,0,0));
	m_pen2Black.CreatePen(PS_SOLID, 2 * m_nLineWidthMul, RGB(0,0,0));
	m_pen3Black.CreatePen(PS_SOLID, 3 * m_nLineWidthMul, RGB(0,0,0));

	m_penGuidline.CreatePen(PS_DOT, 1 * m_nLineWidthMul, RGB(200,200,0));

	m_penRed.CreatePen(PS_SOLID, 1 * m_nLineWidthMul, RGB(255,0,0));
	m_penBlue.CreatePen(PS_SOLID,1  * m_nLineWidthMul,RGB(0,0,255));

	
	return TRUE;
}

BOOL CGaitAnaly::EndDraw(BOOL bDrawInCtrl/* = TRUE*/)
{
	m_MemDC.SelectObject(m_pOldBitmap);
	
	m_brushWhite.DeleteObject();
	m_brushWAColor.DeleteObject();
	m_brushRed.DeleteObject();
	m_brushBlue.DeleteObject();
	m_brushBlack.DeleteObject();

	m_pen1Black.DeleteObject();
	m_pen2Black.DeleteObject();
	m_pen3Black.DeleteObject();
	m_penGuidline.DeleteObject();

	m_penRed.DeleteObject();
	m_penBlue.DeleteObject();
	
	m_MemDC.DeleteDC();
	m_MemBitmap.DeleteObject();
	
	if(bDrawInCtrl)
	{
		m_pDC->DeleteDC();
	}

	return TRUE;
}

BOOL CGaitAnaly::DrawGaitGraph(int nDestPosX/* = 0*/, int nDestPosY/* = 0*/)
{
	double dLenAxisX = m_rectCtrl.Width() * (1 - MARGIN_RATIO * 2);
	double dLenAxisY = m_rectCtrl.Height() * (1 - MARGIN_RATIO * 2);

	double dPixelNumPerDataX = dLenAxisX / GAIT_POINT_ARRAY_SIZE;
	double dPixelNumPerDataY = dLenAxisY / GAIT_NUMBER_RANGE;

	//  White background
	m_MemDC.FillRect(m_rectCtrl, &m_brushWhite);

	//  X/Y axis: 3 pixel width
	m_MemDC.SelectObject(&m_pen3Black);

	// X axis
	m_MemDC.MoveTo(m_ptZero);
	m_MemDC.LineTo(m_ptZero.x + dLenAxisX, m_ptZero.y);

	// Y axis
	m_MemDC.MoveTo(m_ptZero);
	m_MemDC.LineTo(m_ptZero.x, m_ptZero.y - dLenAxisY);

	//  Scale: 2 pixel width
	m_MemDC.SelectObject(&m_pen2Black);

	//  pixel per scale
 	double dPixelNumPerScaleX = (GAIT_POINT_ARRAY_SIZE * dPixelNumPerDataX) / GAIT_X_SCALE_NUM;

	//  Scale in X axis
	for(int i = 0; i < GAIT_X_SCALE_NUM + 1; i++)
	{
		CPoint ptScale(m_ptZero.x + dPixelNumPerScaleX * i, m_ptZero.y);

		m_MemDC.MoveTo(ptScale);
		m_MemDC.LineTo(ptScale.x, ptScale.y - ((i%5) ? 3 : 5) );

		CString strNum;
		strNum.Format(_T("%d"), i);
		m_MemDC.TextOut(ptScale.x - (i < 10 ? 5 : 7), ptScale.y + 5, strNum);
	}
	
	CString strTime = GetResString(IDS_RT_TIME_IN_GAIT);
	int nXTime = m_ptZero.x + dLenAxisX + 2;
	int nYTime = m_ptZero.y - 9;
	m_MemDC.TextOut(nXTime, nYTime, strTime);

	//  pixel per scale
	double dPixelNumPerScaleY = (GAIT_NUMBER_RANGE * dPixelNumPerDataY) / GAIT_Y_SCALE_NUM;

	//  Scale in Y axis
	for(i = 1 ; i < GAIT_Y_SCALE_NUM + 1; i++)
	{
		// Draw number
		CString strNum;
		strNum.Format(_T("%d"), i * GAIT_NUMBER_RANGE / GAIT_Y_SCALE_NUM);
		m_MemDC.TextOut(m_ptZero.x - (m_rectCtrl.Width() / 15.0), m_ptZero.y - dPixelNumPerScaleY * i - (m_rectCtrl.Height() / 50.0), strNum);
	}
	
	//  Draw guid lines, horizontal
	m_MemDC.SelectObject(&m_penGuidline);
	for(i = 1 ; i < GAIT_Y_SCALE_NUM + 1; i++)
	{
		m_MemDC.MoveTo(m_ptZero.x, m_ptZero.y - dPixelNumPerScaleY * i);
		m_MemDC.LineTo(m_ptZero.x + dLenAxisX, m_ptZero.y - dPixelNumPerScaleY * i);
	}
	//  Draw guid lines, vertical
	for(i = 1 ; i < GAIT_X_SCALE_NUM + 1; i++)
	{
		CPoint ptScale(m_ptZero.x + dPixelNumPerScaleX * i, m_ptZero.y);
		m_MemDC.MoveTo(ptScale);
		m_MemDC.LineTo(ptScale.x, ptScale.y - dLenAxisY);
	}

	CString strNum = GetResString(IDS_RT_NUM_IN_GAIT);
	int nXNum = m_ptZero.x - (m_rectCtrl.Width() / 15.0);
	int nYNum = m_ptZero.y - dLenAxisY - (m_rectCtrl.Height() / 12.0);
	m_MemDC.TextOut(nXNum, nYNum, strNum);

	//  Draw open threshold line, blue
	m_MemDC.SelectObject(&m_penBlue);
	m_MemDC.MoveTo(m_ptZero.x + 2, m_ptZero.y - dPixelNumPerDataY * m_BasicPara.dwOpenThr);
	m_MemDC.LineTo(m_ptZero.x + dLenAxisX, m_ptZero.y - dPixelNumPerDataY * m_BasicPara.dwOpenThr);
	
	//  Draw close threshold line, red
	m_MemDC.SelectObject(&m_penRed);
	m_MemDC.MoveTo(m_ptZero.x + 2, m_ptZero.y - dPixelNumPerDataY * m_BasicPara.dwCloseThr);
	m_MemDC.LineTo(m_ptZero.x + dLenAxisX, m_ptZero.y - dPixelNumPerDataY * m_BasicPara.dwCloseThr);

	//  Top indicator
	CSize sizeIDSize = m_MemDC.GetTextExtent(m_strDevID);
	int nIndicatorY = m_ptZero.y - dLenAxisY - sizeIDSize.cy;

	//  Draw device id
	int nID_X = m_ptZero.x + dLenAxisX * (TOP_INDICATOR_BLOCK_WIDTH * 1.5);
	m_MemDC.TextOut(nID_X, nIndicatorY, m_strDevID);

	//  Draw WA color
	if(m_dwCommVer >= 0x12)
	{
		CRect rectColor;
		rectColor.left		= nID_X + sizeIDSize.cx;
		rectColor.top		= nIndicatorY;
		rectColor.right		= rectColor.left + dLenAxisX * TOP_INDICATOR_BLOCK_WIDTH * 2;
		rectColor.bottom	= rectColor.top + sizeIDSize.cy;
		m_MemDC.FillRect(rectColor, &m_brushWAColor);
	}

	//  Draw Gait Number
	int nGaitText_X = m_ptZero.x + dLenAxisX * (TOP_INDICATOR_BLOCK_WIDTH * 8 + TOP_INDICATOR_INDI_MARGIN * 2);
	m_MemDC.TextOut(nGaitText_X, nIndicatorY, strNum);
	CSize sizeNumSize = m_MemDC.GetTextExtent(strNum);

	CRect rectIndicator;
	rectIndicator.left		= nGaitText_X + sizeNumSize.cx;
	rectIndicator.top		= nIndicatorY + sizeNumSize.cy * 0.4;
	rectIndicator.right		= rectIndicator.left + dLenAxisX * TOP_INDICATOR_BLOCK_WIDTH;
	rectIndicator.bottom	= rectIndicator.top + sizeNumSize.cy * 0.3;
	m_MemDC.FillRect(rectIndicator, &m_brushBlack);

	//  Draw Open Number
	int nOpenText_X = m_ptZero.x + dLenAxisX * (TOP_INDICATOR_BLOCK_WIDTH * 11.5 + TOP_INDICATOR_INDI_MARGIN * 3);
	CString strOpenNumber = GetResString(IDS_RT_OPEN_NUMBER);
	m_MemDC.TextOut(nOpenText_X, nIndicatorY, strOpenNumber);
	CSize sizeOpenSize = m_MemDC.GetTextExtent(strOpenNumber);

	rectIndicator.left		= nOpenText_X + sizeOpenSize.cx;
	rectIndicator.right		= rectIndicator.left + dLenAxisX * TOP_INDICATOR_BLOCK_WIDTH;
	m_MemDC.FillRect(rectIndicator, &m_brushBlue);

	//  Draw Close Number
	int nCloseText_X = m_ptZero.x + dLenAxisX * (TOP_INDICATOR_BLOCK_WIDTH * 15 + TOP_INDICATOR_INDI_MARGIN * 4);
	CString strCloseNumber = GetResString(IDS_RT_CLOSE_NUMBER);
	m_MemDC.TextOut(nCloseText_X, nIndicatorY, strCloseNumber);
	CSize sizeCloseSize = m_MemDC.GetTextExtent(strCloseNumber);

	rectIndicator.left		= nCloseText_X + sizeCloseSize.cx;
	rectIndicator.right		= rectIndicator.left + dLenAxisX * TOP_INDICATOR_BLOCK_WIDTH;
	m_MemDC.FillRect(rectIndicator, &m_brushRed);

	//  Gait: 1 pixel width
	CPen* pPenForGaitCurve = (m_rectCtrl.Height() / 300) < 2 ? &m_pen1Black : &m_pen2Black;
	m_MemDC.SelectObject(pPenForGaitCurve);

	int nPos = m_nArrayPos + 1;
	for(i = 0; i < GAIT_POINT_ARRAY_SIZE - 1; i++)
	{
		if(nPos >= GAIT_POINT_ARRAY_SIZE)
			nPos = 0;

		int nX1 = m_ptZero.x + i * dPixelNumPerDataX;
		int nY1 = m_ptZero.y - m_aGaitPoints[nPos] * dPixelNumPerDataY;

		nPos++;
		if(nPos >= GAIT_POINT_ARRAY_SIZE)
			nPos = 0;

		int nX2 = nX1 + dPixelNumPerDataX;
		int nY2 = m_ptZero.y - m_aGaitPoints[nPos] * dPixelNumPerDataY;

		if(m_ptZero.y != nY1)
		{
			m_MemDC.MoveTo(nX1, nY1);
			m_MemDC.LineTo(nX2, nY2);
		}
	}

	if(!IsDrawPaused())
		RefreshStiOpenCloseValue(dPixelNumPerDataX, dPixelNumPerDataY, dLenAxisX, dLenAxisY);

	m_pDC->BitBlt(nDestPosX, nDestPosY, m_rectCtrl.Width(), m_rectCtrl.Height(), &m_MemDC, 0, 0, SRCCOPY);

	return TRUE;
}

BOOL CGaitAnaly::DrawStopGraph()
{
	double dLenAxisX = m_rectCtrl.Width() * (1 - MARGIN_RATIO * 2);
	double dLenAxisY = m_rectCtrl.Height() * (1 - MARGIN_RATIO * 2);

	CString strGaitStopped = GetResString(IDS_RT_GAIT_STOPPED);
	int nX = m_ptZero.x + dLenAxisX / 2 - 75;
	int nY = m_ptZero.y - dLenAxisY / 2 - 20;
	m_MemDC.TextOut(nX, nY, strGaitStopped);

	m_pDC->BitBlt(0, 0, m_rectCtrl.Width(), m_rectCtrl.Height(), &m_MemDC, 0, 0, SRCCOPY);
	return TRUE;
}


BOOL CGaitAnaly::InitGait(CDC* pDC, CRect rectRange, DWORD aGaitArray[], int nStartPosInArray)
{
	m_pDC = pDC;
	m_rectCtrl = rectRange;
	memcpy(m_aGaitPoints, aGaitArray, sizeof(m_aGaitPoints));
	m_nArrayPos = nStartPosInArray;

	return TRUE;
}


BOOL CGaitAnaly::BeginDrawPrintGaitGraph(int nDestPosX, int nDestPosY)
{
	BeginDraw(FALSE);
	DrawGaitGraph(nDestPosX, nDestPosY);

	return TRUE;
}

BOOL CGaitAnaly::EndDrawPrintGaitGraph()
{
	EndDraw(FALSE);
	
	return TRUE;
}

BOOL CGaitAnaly::DrawGaitCurve(DWORD aGaitArray[], int nStartPosInArray, int nDestPosX, int nDestPosY)
{
	memcpy(m_aGaitPoints, aGaitArray, sizeof(m_aGaitPoints));
	m_nArrayPos = nStartPosInArray;
	
	double dLenAxisX = m_rectCtrl.Width() * (1 - MARGIN_RATIO * 2);
	double dLenAxisY = m_rectCtrl.Height() * (1 - MARGIN_RATIO * 2);

	double dPixelNumPerDataX = dLenAxisX / GAIT_POINT_ARRAY_SIZE;
	double dPixelNumPerDataY = dLenAxisY / GAIT_NUMBER_RANGE;

	int nPos = m_nArrayPos + 1;
	for(int i = 0; i < GAIT_POINT_ARRAY_SIZE - 1; i++)
	{
		if(nPos >= GAIT_POINT_ARRAY_SIZE)
			nPos = 0;
		
		int nX1 = m_ptZero.x + i * dPixelNumPerDataX;
		int nY1 = m_ptZero.y - m_aGaitPoints[nPos] * dPixelNumPerDataY;
		
		nPos++;
		if(nPos >= GAIT_POINT_ARRAY_SIZE)
			nPos = 0;
		
		int nX2 = nX1 + dPixelNumPerDataX;
		int nY2 = m_ptZero.y - m_aGaitPoints[nPos] * dPixelNumPerDataY;
		
		if(m_ptZero.y != nY1)
		{
			m_MemDC.MoveTo(nX1, nY1);
			m_MemDC.LineTo(nX2, nY2);
		}
	}
	
	m_pDC->BitBlt(nDestPosX, nDestPosY, m_rectCtrl.Width(), m_rectCtrl.Height(), &m_MemDC, 0, 0, SRCCOPY);

	return TRUE;
}

BOOL CGaitAnaly::GetGaitSnap(DWORD aGaitArray[], int* pnArrayStartPos, DWORD* pdwStiOpen, DWORD* pdwStiClose)
{
	if(aGaitArray == NULL || pnArrayStartPos == NULL || pdwStiOpen == NULL || pdwStiClose == NULL)
		return FALSE;

	memcpy(aGaitArray, m_aGaitPoints, sizeof(m_aGaitPoints));
	*pnArrayStartPos = m_nArrayPos;
	*pdwStiOpen = m_BasicPara.dwOpenThr;
	*pdwStiClose = m_BasicPara.dwCloseThr;

	return TRUE;
}

BOOL CGaitAnaly::SnapGait(DWORD dwMRNCode, int nDiagSN)	// nDiagSN == -1, it means it snap in RealTime Monitor
{
	ASSERT(nDiagSN >= 0 || nDiagSN == -1);

	DWORD aGaitValues[GAIT_POINT_ARRAY_SIZE] = {0};
	int nStartPos = 0;
	DWORD dwTriggerOpen = 0;
	DWORD dwTriggerClose = 0;
	
	BOOL bGetOK = GetGaitSnap(aGaitValues, &nStartPos, &dwTriggerOpen, &dwTriggerClose);
	if(bGetOK)
	{
		CString strGaitVales;
		for(int i = 0; i < GAIT_POINT_ARRAY_SIZE; i++)
		{
			DWORD dwGait = aGaitValues[i];
			CString strGait;
			strGait.Format(_T("%x%x"), ((dwGait & 0xf0) >> 4), (dwGait & 0xf) );
			
			strGaitVales += strGait;
		}
		
		// nStartPos maybe -1
		if(nStartPos < 0)
			nStartPos = 0;

		CTime curTime = CTime::GetCurrentTime();
		CString strSnapDate;
		strSnapDate.Format(_T("%4d-%02d-%02d"), curTime.GetYear(), curTime.GetMonth(), curTime.GetDay());
		
		//  The record exists?
		CString strSQL;
		if(nDiagSN == -1)
			strSQL.Format(_T("SELECT COUNT(MRNCode) AS RecCnt FROM GaitSnap WHERE MRNCode=%d AND DiagSN=-1 AND SnapDate='%s'"), dwMRNCode, strSnapDate);
		else
			strSQL.Format(_T("SELECT COUNT(MRNCode) AS RecCnt FROM GaitSnap WHERE MRNCode=%d AND DiagSN=%d"), dwMRNCode, nDiagSN);

		CGYDataSet setSnap;
		setSnap.OpenTable(strSQL);

		CString strRecCnt;
		setSnap.GetFieldValue(_T("RecCnt"), strRecCnt);
		int nRecCnt = _ttoi(strRecCnt);
		if(nRecCnt > 0)
		{
			if(nDiagSN == -1)
				strSQL.Format(_T("UPDATE GaitSnap SET TriggerOpen=%d, TriggerClose=%d, StartPos=%d, GaitValue='%s' WHERE MRNCode=%d AND DiagSN=-1 AND SnapDate='%s'"), 
														dwTriggerOpen, dwTriggerClose,	nStartPos, 	strGaitVales,		dwMRNCode,						strSnapDate);
			else
				strSQL.Format(_T("UPDATE GaitSnap SET TriggerOpen=%d, TriggerClose=%d, StartPos=%d, SnapDate='%s', GaitValue='%s' WHERE MRNCode=%d AND DiagSN=%d"), 
														dwTriggerOpen, dwTriggerClose,	nStartPos, strSnapDate,		strGaitVales,		dwMRNCode,		nDiagSN);
		}
		else
		{
			strSQL.Format(_T("INSERT INTO GaitSnap (MRNCode, DiagSN, SnapDate, TriggerOpen, TriggerClose, StartPos, GaitValue) VALUES (%d, %d, '%s', %d, %d, %d, '%s')"), 
											dwMRNCode, nDiagSN, strSnapDate, dwTriggerOpen, dwTriggerClose, nStartPos, strGaitVales);
		}
		
		if(setSnap.ExecuteSQL(strSQL))
		{
			return TRUE;
		}
		else
		{
			DataErrorMsgBox(__FILE__, __LINE__, strSQL, setSnap.GetLastErrorString());
			return FALSE;
		}
	}

	GYMsgBox(IDS_RT_WRITE_GAIT_ERROR, MB_ICONSTOP);
	return FALSE;
}

BOOL CGaitAnaly::ReadGaitFromTable(DWORD dwMRNCode, int nDiagSN, CString strDate, DWORD dwGaitPoints[], int* pnStartPos, int* pnTriggerOpen, int* pnTriggerClose, CString* pstrDevID, CString* pstrDevAddress)
{
	ASSERT(nDiagSN == -1 || nDiagSN >= 0);

	if(nDiagSN == -1 && strDate.IsEmpty())
		return FALSE;

	CString strSQL;
	strSQL.Format(_T("SELECT MedicalRecordNo FROM PatientInfo WHERE SerialNo=%d"), dwMRNCode);
	CGYDataSet setPatInfo(strSQL);
	if(setPatInfo.IsEOF())
	{
		ASSERT(FALSE);
		return FALSE;
	}

	CString strMRN;
	setPatInfo.GetFieldValue(_T("MedicalRecordNo"), strMRN);
	setPatInfo.Close();

	strSQL.Format(_T("SELECT WADevID, WAAddress FROM DiagRecord WHERE MedicalRecordNo='%s' AND DiagSN=%d"), strMRN, nDiagSN);
	CGYDataSet setDiagRec(strSQL);
	if(setDiagRec.IsEOF())
	{
		ASSERT(FALSE);
		return FALSE;
	}
	CString strDevID;
	CString strDevAddress;
	setDiagRec.GetFieldValue(_T("WADevID"), strDevID);
	setDiagRec.GetFieldValue(_T("WAAddress"), strDevAddress);
	setDiagRec.Close();

	*pstrDevID = strDevID;
	*pstrDevAddress = strDevAddress;

	if(nDiagSN == -1)
		strSQL.Format(_T("SELECT TriggerOpen, TriggerClose, StartPos, GaitValue FROM GaitSnap WHERE MRNCode=%d AND DiagSN=-1 AND SnapDate='%s'"), dwMRNCode, strDate);
	else
		strSQL.Format(_T("SELECT TriggerOpen, TriggerClose, StartPos, GaitValue FROM GaitSnap WHERE MRNCode=%d AND DiagSN=%d"), dwMRNCode, nDiagSN);
	
	CGYDataSet setGait(strSQL);
	if(setGait.IsEOF())
		return FALSE;
	
	CString strTriggerOpen, strTriggerClose, strStartPos, strGaitValues;
	setGait.GetFieldValue(_T("TriggerOpen"), strTriggerOpen);
	setGait.GetFieldValue(_T("TriggerClose"), strTriggerClose);
	setGait.GetFieldValue(_T("StartPos"), strStartPos);
	setGait.GetFieldValue(_T("GaitValue"), strGaitValues);

	int nGaitStrLen = strGaitValues.GetLength();
	if(nGaitStrLen != GAIT_POINT_ARRAY_SIZE * 2)
		return FALSE;
	
	*pnStartPos		= _ttoi(strStartPos);
	*pnTriggerOpen	= _ttoi(strTriggerOpen);
	*pnTriggerClose	= _ttoi(strTriggerClose);

	// nStartPos maybe -1
	if(*pnStartPos < 0)
		*pnStartPos = 0;
	
	for(int i = 0; i < GAIT_POINT_ARRAY_SIZE; i++)
	{
		CString strByte = strGaitValues.Mid(i * 2, 2);
		DWORD dwGait = _tcstoul(strByte, NULL, 16);
		dwGaitPoints[i] = dwGait;
	}

	return TRUE;
}

BOOL CGaitAnaly::ShowStaticGaitSnap(CWnd* pCtrl, int nDiagSN)
{
	if(!pCtrl || nDiagSN < 0)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	//  Show Static Gait Snap
	int nStartPos = 0;
	int nTriggerOpen = 0;
	int nTriggerClose = 0;
	
	DWORD dwGaitPoints[GAIT_POINT_ARRAY_SIZE] = {0};
	CString strDevID;
	CString strDevAddress;
	BOOL bRet = CGaitAnaly::ReadGaitFromTable(GetApp()->GetCurSN(), nDiagSN, _T(""), dwGaitPoints, &nStartPos, &nTriggerOpen, &nTriggerClose, &strDevID, &strDevAddress);
	if(!bRet)
		return FALSE;

	return ShowGaitInCtrl(pCtrl, dwGaitPoints, nStartPos, nTriggerOpen, nTriggerClose, strDevID, strDevAddress);
}

BOOL CGaitAnaly::ShowGaitInCtrl(CWnd* pCtrl, DWORD adwGaitPoints[], int nStartPos, DWORD dwStiOpen, DWORD dwStiClose, CString strDevID, CString strDevAddress)
{
	if(pCtrl == NULL || adwGaitPoints == NULL || nStartPos < 0 || dwStiOpen > 255 || dwStiClose > 255)
		return FALSE;

	//  Get Color
	DWORD dwCommVer = 0;
	COLORREF crWAColor = RGB(255, 255, 255);
	CString strSQL;
	strSQL.Format(_T("SELECT ColorIndex FROM WAColor WHERE WAAddress='%s'"), strDevAddress);
	CGYDataSet setColor(strSQL);
	if(!setColor.IsEOF())
	{
		CString strColorIndex;
		setColor.GetFieldValue(_T("ColorIndex"), strColorIndex);

		DWORD dwColorIndex = _ttoi(strColorIndex);
		dwColorIndex = min(dwColorIndex, 4);
		dwColorIndex = max(dwColorIndex, 0);
		crWAColor = CColorComboBox::GetWAColor(dwColorIndex);

		dwCommVer = 0x12;
	}
	setColor.Close();
	
	CRect rectCtrl;
	pCtrl->GetClientRect(&rectCtrl);
	
	CDC* pDC = pCtrl->GetDC();
	NULL_RETURN_FALSE(pDC);

	WA_BASIC_PARA wbp = {0};
	wbp.dwSize = sizeof(WA_BASIC_PARA);
	wbp.dwOpenThr = dwStiOpen;
	wbp.dwCloseThr = dwStiClose;

	CGaitAnaly ga;
	ga.InitGait(pDC, rectCtrl, adwGaitPoints, nStartPos);
	ga.SetGaitPara(&wbp);
	ga.PauseDraw(TRUE);
	ga.SetDevID(strDevID);
	ga.SetCommVer(dwCommVer);
	ga.SetWAColor(crWAColor);
	ga.BeginDrawPrintGaitGraph(0, 0);
	ga.EndDrawPrintGaitGraph();
	
	pDC->DeleteDC();	
	
	return TRUE;
}

BOOL CGaitAnaly::HasSdiagSnapGait(DWORD dwMRNCode, int nDiagSN)
{
	if(dwMRNCode == 0)
		return FALSE;
	
	CString strSQL;
	strSQL.Format(_T("SELECT COUNT(*) AS GaitCount FROM GaitSnap WHERE MRNCode=%d AND DiagSN=%d"), dwMRNCode, nDiagSN);
	
	CGYDataSet setSnapGait(strSQL);
	if(setSnapGait.IsEOF())
		return FALSE;
	
	CString strGaitCnt;
	setSnapGait.GetFieldValue(_T("GaitCount"), strGaitCnt);
	
	return (_ttoi(strGaitCnt) > 0);
}

void CGaitAnaly::RefreshStiOpenCloseValue(double dPixelNumPerDataX, double dPixelNumPerDataY, double dLenAxisX, double dLenAxisY)
{
	DWORD aCrestTrough[GAIT_POINT_ARRAY_SIZE];
	ZERO_ARRAY(aCrestTrough);
	
	DWORD aGaitValue[GAIT_POINT_ARRAY_SIZE];
	
	memcpy( aGaitValue, &m_aGaitPoints[m_nArrayPos], (GAIT_POINT_ARRAY_SIZE - m_nArrayPos) * sizeof(DWORD) );
	memcpy( &aGaitValue[GAIT_POINT_ARRAY_SIZE - m_nArrayPos], m_aGaitPoints, m_nArrayPos * sizeof(DWORD) );
	
	DWORD dwOpenValue	= 0;
	DWORD dwCloseValue	= 0;

	DWORD dwMaxGait		= 0;
	DWORD dwMinGait		= 0;
	DWORD dwAverageGait	= 0;

#ifdef THIGH_WA_MODE
	if(GetSmartWAParam(aGaitValue, GAIT_POINT_ARRAY_SIZE, &dwCloseValue, &dwOpenValue, aCrestTrough, &dwMinGait, &dwMaxGait, &dwAverageGait))
#else
	if(GetSmartWAParam(aGaitValue, GAIT_POINT_ARRAY_SIZE, &dwOpenValue, &dwCloseValue, aCrestTrough, &dwMinGait, &dwMaxGait, &dwAverageGait))
#endif
	{
		
#ifdef _DEBUG
		for(int j = 0; j < GAIT_POINT_ARRAY_SIZE; j++ )
		{
			if(aCrestTrough[j] != WAVE_COMMON_FLAG)
			{
				int nX1 = m_ptZero.x + j * dPixelNumPerDataX;
				int nY1 = m_ptZero.y - aGaitValue[j] * dPixelNumPerDataY;
				
				m_MemDC.MoveTo(nX1 - 15, nY1);
				m_MemDC.LineTo(nX1 + 15, nY1);
			}
		}

		m_MemDC.SelectObject(&m_pen2Black);
		m_MemDC.MoveTo(m_ptZero.x + 2, m_ptZero.y - dPixelNumPerDataY * dwMaxGait);
		m_MemDC.LineTo(m_ptZero.x + dLenAxisX, m_ptZero.y - dPixelNumPerDataY * dwMaxGait);
		
		m_MemDC.SelectObject(&m_pen2Black);
		m_MemDC.MoveTo(m_ptZero.x + 2, m_ptZero.y - dPixelNumPerDataY * dwMinGait);
		m_MemDC.LineTo(m_ptZero.x + dLenAxisX, m_ptZero.y - dPixelNumPerDataY * dwMinGait);

		m_MemDC.SelectObject(&m_pen1Black);
		m_MemDC.MoveTo(m_ptZero.x + 2, m_ptZero.y - dPixelNumPerDataY * dwAverageGait);
		m_MemDC.LineTo(m_ptZero.x + dLenAxisX, m_ptZero.y - dPixelNumPerDataY * dwAverageGait);
#endif

		HWND hGaitWnd = GetApp()->GetGaitWindow();
		if(hGaitWnd && ::IsWindow(hGaitWnd))
			PostMessage(hGaitWnd, GYWA_MSG_REALTIME_OPEN_CLOSE_VALUE, dwOpenValue, dwCloseValue);
	}
}
